<!doctype html><html lang=zh-cn dir=ltr>
<head><meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="最近一直在写 Vue, 在公司的项目里使用的是Composition Api + Vue2 的组合. (因为公司里考虑到同事的技能树, 没有用vue3和Typescipt).
CA 是 Vue3 追加的全新 API. 用到 Vue2 里可能有点怪怪的.
不过 CA 是以 Vue-Plugin 的方式提供的 API, 所以使用起来非常方便. 同时也鼓励更多人使用这个API.
首先是关于这个API的使用方式, 以前的代码需要将方法卸载method区块中, 每个变量和方法之间的关系很模糊暧昧.
需要开发者自己去找关于每个方法和变量之间的关系, 用CA之后可以写出类似ReactHook风格的代码.
// OA (Option API 原版的API是这样称呼的) {  data: {  count: 1  },  methods: {  sub(num: number) {  // ...  },  add(num: number) {  // ...  }  } } // CA const count = ref(1); const { add, sub } = useCount();  add(1); sub(2);  function useCount(count: Ref&amp;lt;number&amp;gt;) {  function sub(num: number) {  // ."><title>Composition Api</title><link rel=canonical href=https://sdttttt.github.io/blog/composition-api/>
<link rel=stylesheet href=/scss/style.min.b80bf249ce4a22cf55e8d7340a0b37a2f2c10f54f3a9a49cb94b694a2eb0bbea.css><meta property="og:title" content="Composition Api">
<meta property="og:description" content="最近一直在写 Vue, 在公司的项目里使用的是Composition Api + Vue2 的组合. (因为公司里考虑到同事的技能树, 没有用vue3和Typescipt).
CA 是 Vue3 追加的全新 API. 用到 Vue2 里可能有点怪怪的.
不过 CA 是以 Vue-Plugin 的方式提供的 API, 所以使用起来非常方便. 同时也鼓励更多人使用这个API.
首先是关于这个API的使用方式, 以前的代码需要将方法卸载method区块中, 每个变量和方法之间的关系很模糊暧昧.
需要开发者自己去找关于每个方法和变量之间的关系, 用CA之后可以写出类似ReactHook风格的代码.
// OA (Option API 原版的API是这样称呼的) {  data: {  count: 1  },  methods: {  sub(num: number) {  // ...  },  add(num: number) {  // ...  }  } } // CA const count = ref(1); const { add, sub } = useCount();  add(1); sub(2);  function useCount(count: Ref&amp;lt;number&amp;gt;) {  function sub(num: number) {  // .">
<meta property="og:url" content="https://sdttttt.github.io/blog/composition-api/">
<meta property="og:site_name" content="SDTTTTT">
<meta property="og:type" content="article"><meta property="article:section" content="Blog"><meta property="article:published_time" content="2021-01-14T10:29:36+08:00"><meta property="article:modified_time" content="2021-01-25T12:34:23+08:00">
<meta name=twitter:title content="Composition Api">
<meta name=twitter:description content="最近一直在写 Vue, 在公司的项目里使用的是Composition Api + Vue2 的组合. (因为公司里考虑到同事的技能树, 没有用vue3和Typescipt).
CA 是 Vue3 追加的全新 API. 用到 Vue2 里可能有点怪怪的.
不过 CA 是以 Vue-Plugin 的方式提供的 API, 所以使用起来非常方便. 同时也鼓励更多人使用这个API.
首先是关于这个API的使用方式, 以前的代码需要将方法卸载method区块中, 每个变量和方法之间的关系很模糊暧昧.
需要开发者自己去找关于每个方法和变量之间的关系, 用CA之后可以写出类似ReactHook风格的代码.
// OA (Option API 原版的API是这样称呼的) {  data: {  count: 1  },  methods: {  sub(num: number) {  // ...  },  add(num: number) {  // ...  }  } } // CA const count = ref(1); const { add, sub } = useCount();  add(1); sub(2);  function useCount(count: Ref&amp;lt;number&amp;gt;) {  function sub(num: number) {  // .">
</head><body class=article-page>
<script>(function(){const e="StackColorScheme";localStorage.getItem(e)||localStorage.setItem(e,"auto")})()</script><script>(function(){const t="StackColorScheme",e=localStorage.getItem(t),n=window.matchMedia("(prefers-color-scheme: dark)").matches===!0;e=="dark"||e==="auto"&&n?document.documentElement.dataset.scheme="dark":document.documentElement.dataset.scheme="light"})()</script>
<div class="container main-container flex on-phone--column compact"><aside class="sidebar left-sidebar sticky">
<button class="hamburger hamburger--spin" type=button id=toggle-menu aria-label="Toggle Menu">
<span class=hamburger-box>
<span class=hamburger-inner></span>
</span>
</button>
<header>
<figure class=site-avatar>
<a href=/>
<img src=/img/avatar_hu8e30117ca872857dd9f41f234a693048_441529_300x0_resize_box_3.png width=300 height=300 class=site-logo loading=lazy alt=Avatar>
</a>
</figure><div class=site-meta>
<h1 class=site-name><a href=/>SDTTTTT</a></h1><h2 class=site-description>臭鱼烂虾</h2></div></header><ol class=menu id=main-menu>
<div class=menu-bottom-section>
<li id=dark-mode-toggle><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-toggle-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="8" cy="12" r="2"/><rect x="2" y="6" width="20" height="12" rx="6"/></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-toggle-right" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="16" cy="12" r="2"/><rect x="2" y="6" width="20" height="12" rx="6"/></svg>
<span>Dark Mode</span>
</li></div></ol></aside><main class="main full-width">
<article class=main-article>
<header class=article-header>
<div class=article-details>
<div class=article-title-wrapper>
<h2 class=article-title>
<a href=/blog/composition-api/>Composition Api</a>
</h2></div><footer class=article-time>
<div><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-calendar-time" width="56" height="56" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><path d="M11.795 21H5a2 2 0 01-2-2V7a2 2 0 012-2h12a2 2 0 012 2v4"/><circle cx="18" cy="18" r="4"/><path d="M15 3v4"/><path d="M7 3v4"/><path d="M3 11h16"/><path d="M18 16.496V18l1 1"/></svg>
<time class=article-time--published>Jan 14, 2021</time>
</div><div><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clock" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 15"/></svg>
<time class=article-time--reading>
1 minute read
</time>
</div></footer></div></header><section class=article-content>
<p>最近一直在写 Vue, 在公司的项目里使用的是<code>Composition Api</code> + Vue2 的组合. <em>(因为公司里考虑到同事的技能树, 没有用vue3和Typescipt)</em>.</p><p>CA 是 Vue3 追加的全新 API. 用到 Vue2 里可能有点怪怪的.</p><p>不过 CA 是以 Vue-Plugin 的方式提供的 API, 所以使用起来非常方便.
同时也鼓励更多人使用这个API.</p><p>首先是关于这个API的使用方式, 以前的代码需要将方法卸载method区块中, 每个变量和方法之间的关系很模糊暧昧.<br>
需要开发者自己去找关于每个方法和变量之间的关系, 用CA之后可以写出类似ReactHook风格的代码.</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-typescript data-lang=typescript><span style=display:flex><span><span style=color:#75715e>// OA (Option API 原版的API是这样称呼的)
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>{
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>data</span><span style=color:#f92672>:</span> {
</span></span><span style=display:flex><span>        <span style=color:#a6e22e>count</span>: <span style=color:#66d9ef>1</span>
</span></span><span style=display:flex><span>    },
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>methods</span><span style=color:#f92672>:</span> {
</span></span><span style=display:flex><span>        <span style=color:#a6e22e>sub</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>            <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>        },
</span></span><span style=display:flex><span>        <span style=color:#a6e22e>add</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>            <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>        }
</span></span><span style=display:flex><span>    }
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span><span style=color:#75715e>// CA
</span></span></span><span style=display:flex><span><span style=color:#75715e></span><span style=color:#66d9ef>const</span> <span style=color:#a6e22e>count</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>ref</span>(<span style=color:#ae81ff>1</span>);
</span></span><span style=display:flex><span><span style=color:#66d9ef>const</span> { <span style=color:#a6e22e>add</span>, <span style=color:#a6e22e>sub</span> } <span style=color:#f92672>=</span> <span style=color:#a6e22e>useCount</span>();
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>add</span>(<span style=color:#ae81ff>1</span>);
</span></span><span style=display:flex><span><span style=color:#a6e22e>sub</span>(<span style=color:#ae81ff>2</span>);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>function</span> <span style=color:#a6e22e>useCount</span>(<span style=color:#a6e22e>count</span>: <span style=color:#66d9ef>Ref</span>&lt;<span style=color:#f92672>number</span>&gt;) {
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>sub</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>            <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>        },
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>add</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>        <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>    }
</span></span><span style=display:flex><span>}
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#75715e>// 当然你也可以像ReactHook那样写， 完全没有问题，看你的个人口味
</span></span></span><span style=display:flex><span><span style=color:#75715e></span><span style=color:#66d9ef>const</span> { <span style=color:#a6e22e>count</span>, <span style=color:#a6e22e>add</span>, <span style=color:#a6e22e>sub</span> } <span style=color:#f92672>=</span> <span style=color:#a6e22e>useCount</span>(<span style=color:#ae81ff>0</span>);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>add</span>(<span style=color:#ae81ff>1</span>);
</span></span><span style=display:flex><span><span style=color:#a6e22e>sub</span>(<span style=color:#ae81ff>2</span>);
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>function</span> <span style=color:#a6e22e>useCount</span>(<span style=color:#a6e22e>count</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>const</span> <span style=color:#a6e22e>count</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>ref</span>(<span style=color:#a6e22e>count</span>);
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>sub</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>            <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>        },
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>function</span> <span style=color:#a6e22e>add</span>(<span style=color:#a6e22e>num</span>: <span style=color:#66d9ef>number</span>) {
</span></span><span style=display:flex><span>        <span style=color:#75715e>// ...
</span></span></span><span style=display:flex><span><span style=color:#75715e></span>    }
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>我目前写CA大概就是这样编写的. 根据一个响应数据的关系编写改变它的一系列动作.
这样逻辑拆分的很清楚. 查看起来也比较方便.</p><hr>
<p>不过这套API目前的缺点也比较明显, 在开发过程中从Vue2过来的用户很明显能感觉到,
在<code>setup()</code>由于不能使用<code>this</code>所以会有很多开发习惯上的麻烦.</p><p><strong>这里说个关于使用this上挂载对象的方法.</strong> (ctx参数不说了)</p><ul>
<li>
<p>首先就是CA的库中有一个函数,叫做<code>getCurrentInstall</code>. 可以通过该函数获得当前组件的实例. 使用该实例上代理的对象就能控制各种<code>this.$router</code>, <code>this.$refs</code>方法了.</p></li><li>
<p>第二种可以让你使用<code>this</code>, 把动作函数挂载到某个视图按钮上的时候, 在该动作函数里就可以使用<code>this</code>对象. 上面有正常OA可以使用的所有<code>this</code>上挂载的对象.</p></li></ul><p>开发项目的时候还踩了很多坑, 不过都是一些智商问题&mldr; 比如JS的对象传递传递的是<code>Reference</code>, 基本类型是<code>Clone</code>. 因为这个原因有几个视图之间的数据没法实时同步, 害我浪费了一个下午.</p><h3 id=关于-watcheffect>关于 watchEffect</h3><p>这个函数的实现和React Hook中的useEffect有异曲同工之妙,
监听回调函数内依赖的响应式数据的变化来执行回调函数.</p><p>对,没错, 它能监听函数内变化的响应数据并且自动执行回调函数! 是不是很魔法!
连反射都做不到监听函数内依赖的外部变量.</p><p>举个例子:</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-javascript data-lang=javascript><span style=display:flex><span><span style=color:#66d9ef>const</span> <span style=color:#a6e22e>count</span> <span style=color:#f92672>=</span> <span style=color:#a6e22e>ref</span>(<span style=color:#ae81ff>0</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>watchEffect</span>(() =&gt; <span style=color:#a6e22e>console</span>.<span style=color:#a6e22e>log</span>(<span style=color:#a6e22e>count</span>))
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#75715e>// 当count数据发送变化的时候会执行watchEffect内的回调函数
</span></span></span></code></pre></div><p>还有一个watch函数也可以做到类似的操作, 不过需要手动在第一个参数指定监听的响应式数据.
watch的原理就比较容易懂了. 指定了依赖就可以通过挂钩子来实现监听变化执行回调了.</p><p>问题就在watchEffect是怎么做到不指定依赖就能知道回调内依赖了哪个响应式数据?并且自动执行的?</p><p>这个魔法的原理我想破头也没有想出来. 看了一些关于副作用的文章之后才开始理解这个魔法的本质.</p><p><code>watch</code> 和 <code>watchEffect</code> 有一个区别就在于, watchEffect在页面渲染后会首次执行一次.
这个动作就是魔法的秘密了, 执行后watchEffect就能看到那些响应式数数据收到了回调的影响.(不一定是数据的变化)</p></section><footer class=article-footer>
<section class=article-lastmod><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clock" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentcolor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z"/><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 15"/></svg>
<span>
Last updated on Jan 25, 2021 12:34 CST
</span>
</section></footer></article><div id=gitalk-container></div><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.css>
<script src=https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.min.js></script>
<script src=https://cdn.jsdelivr.net/npm/blueimp-md5@2.18.0/js/md5.min.js></script>
<script>const gitalk=new Gitalk({clientID:"97eb9ce8ac126f0c7833",clientSecret:"5da440441b500b0b016928640712a1b1a03a5f8f",repo:"sdttttt/sdttttt.github.io",owner:"sdttttt",admin:["sdttttt"],distractionFreeMode:!1,id:md5(location.pathname)});(function(){if(["localhost","127.0.0.1"].indexOf(window.location.hostname)!=-1){document.getElementById("gitalk-container").innerHTML="Gitalk comments not available by default when the website is previewed locally.";return}gitalk.render("gitalk-container")})()</script>
<footer class=site-footer>
<section class=copyright>
&copy;
2022 SDTTTTT
</section><section class=powerby>
Built with <a href=https://gohugo.io/ target=_blank rel=noopener>Hugo</a> <br>
Theme <b><a href=https://github.com/CaiJimmy/hugo-theme-stack target=_blank rel=noopener data-version=3.10.0>Stack</a></b> designed by <a href=https://jimmycai.com target=_blank rel=noopener>Jimmy</a>
</section></footer><div class=pswp tabindex=-1 role=dialog aria-hidden=true>
<div class=pswp__bg></div><div class=pswp__scroll-wrap>
<div class=pswp__container>
<div class=pswp__item></div><div class=pswp__item></div><div class=pswp__item></div></div><div class="pswp__ui pswp__ui--hidden">
<div class=pswp__top-bar>
<div class=pswp__counter></div><button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--share" title=Share></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<div class=pswp__preloader>
<div class=pswp__preloader__icn>
<div class=pswp__preloader__cut>
<div class=pswp__preloader__donut></div></div></div></div></div><div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class=pswp__share-tooltip></div></div><button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class=pswp__caption>
<div class=pswp__caption__center></div></div></div></div></div><script src=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js integrity="sha256-ePwmChbbvXbsO02lbM3HoHbSHTHFAeChekF1xKJdleo=" crossorigin=anonymous defer></script><script src=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js integrity="sha256-UKkzOn/w1mBxRmLLGrSeyB4e1xbrp4xylgAWb3M42pU=" crossorigin=anonymous defer></script><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.css integrity="sha256-c0uckgykQ9v5k+IqViZOZKc47Jn7KQil4/MP3ySA3F8=" crossorigin=anonymous><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.css integrity="sha256-SBLU4vv6CA6lHsZ1XyTdhyjJxCjPif/TRkjnsyGAGnE=" crossorigin=anonymous>
</main></div><script src=https://cdn.jsdelivr.net/npm/node-vibrant@3.1.5/dist/vibrant.min.js integrity="sha256-5NovOZc4iwiAWTYIFiIM7DxKUXKWvpVEuMEPLzcm5/g=" crossorigin=anonymous></script><script type=text/javascript src=/ts/main.js defer></script>
<script>(function(){const e=document.createElement("link");e.href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap",e.type="text/css",e.rel="stylesheet",document.head.appendChild(e)})()</script>
</body></html>